package com.xiaoyu.base.log

import `in`.srain.cube.cache.DiskFileUtils
import `in`.srain.cube.util.CLog
import `in`.srain.cube.util.Env
import `in`.srain.cube.util.UTUtil
import `in`.srain.cube.util.log.LogClient
import `in`.srain.cube.util.log.LogClientManagerProxy
import `in`.srain.cube.util.log.LogEvent
import android.os.Build
import com.aliyun.sls.android.producer.*
import com.xiaoyu.base.AppConfig
import com.xiaoyu.base.BuildConfig
import com.xiaoyu.base.app.AppContext
import java.io.File

/*
 * see the aliyun sls document: https://github.com/aliyun/aliyun-log-android-sdk?spm=a2c4g.11186623.2.24.73d32e89Is3Wk1
 */
open class BaseLogClient : LogClient {

    companion object {
        const val KEY_UID = "uid"
        const val KEY_PACKAGE_NAME = "packageName"

        private const val TAG = "LogClient"
        private const val endPoint = "cn-hangzhou.log.aliyuncs.com"
        private const val LOG_DIR_NAME = "event-log"
        private const val LOG_SIZE_IN_KB: Long = 1024 * 1024

        private const val KEY_PLATFORM = "platform"
        private const val KEY_ENV = "env"
        private const val KEY_VERSION = "version"
        private const val KEY_MODEL = "model"
        private const val KEY_RELEASE = "release"
        private const val KEY_SDK_INT = "sdkInt"
        private const val KEY_CARRIER = "carrier"

        private val APP_PLATFORM: String = "android"
        private val APP_ENV: String = Env.getEnvTag()
        private val APP_VERSION: String = BuildConfig.VERSION_NAME
        private val APP_MODEL: String = Build.MODEL
        private val APP_RELEASE: String = Build.VERSION.RELEASE
        private val APP_SDK_INT = Build.VERSION.SDK_INT.toString()

        val instance by lazy { BaseLogClient() }
    }

    private val logCallback = LogProducerCallback { resultCode: Int, reqId: String?, errorMessage: String?, logBytes: Int, compressedBytes: Int ->
        if (errorMessage != null) {
            CLog.e(TAG, "%s %s %s %s %s%n", LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes);
        }
    }

    open val logstoreName = "base-service"
    private val projectName = AppConfig.aliyunSlsProjectName()
    private val logDirPath = DiskFileUtils.getDiskCacheDir(AppContext.getContext(), LOG_DIR_NAME, LOG_SIZE_IN_KB)
    private val logPath = logDirPath.path.toString() + File.separator + projectName + "-" + logstoreName
    private val config = LogProducerConfig(endPoint, projectName, logstoreName, AppConfig.aliyunAccessKeyId(), AppConfig.aliyunAccessKeySecret())
    private val client = LogProducerClient(config, logCallback)

    init {
        // 设置主题
        config.setTopic(logstoreName)
        config.setPacketLogBytes(1024 * 1024)
        config.setPacketLogCount(1024)
        config.setPacketTimeout(3000)
        config.setMaxBufferLimit(64 * 1024 * 1024)
        config.setSendThreadCount(1)
        config.setPersistent(1)
        config.setPersistentFilePath(logPath)
        config.setPersistentForceFlush(0)
        config.setPersistentMaxFileCount(10)
        config.setPersistentMaxFileSize(1024 * 1024)
        config.setPersistentMaxLogCount(65536)

        addBaseTag()

        LogClientManagerProxy.addClient(logstoreName, this)
    }

    private fun addBaseTag() {
        addTag(KEY_PLATFORM, APP_PLATFORM)
        addTag(KEY_ENV, APP_ENV)
        addTag(KEY_VERSION, APP_VERSION)
        addTag(KEY_MODEL, APP_MODEL)
        addTag(KEY_RELEASE, APP_RELEASE)
        addTag(KEY_SDK_INT, APP_SDK_INT)
        addTag(KEY_CARRIER, UTUtil.getInstance().carrier)
    }

    override fun addTag(key: String, value: String) {
        config.addTag(key, value)
    }

    override fun addLog(map: Map<String, String>) {
        val log = Log()
        log.content.putAll(map)
        client.addLog(log)
        CLog.d(TAG, "$logstoreName, log=${log.content}")
    }

    override fun addLog(logEvent: LogEvent) {
        val map = mutableMapOf<String, String>()
        for (entry in logEvent.eventData.entries) {
            entry.value?.let {
                map[entry.key] = it.toString()
            }
        }
        addLog(map)
    }
}